package com.hidquat;

import android.opengl.GLSurfaceView;
import android.opengl.GLU;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * Created on 2017/5/16, renderer.
 */

public class STLRenderer implements GLSurfaceView.Renderer{
    private float rotateAngle = 0;
    private float rotateX = 0;
    private float rotateY = 0;
    private float rotateZ = 1;

    private STLObject stlObject;

    public STLRenderer(STLObject stlObject) {
        this.stlObject = stlObject;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glEnable(GL10.GL_BLEND);
        gl.glClearDepthf(1.0f);
        gl.glEnable(GL10.GL_DEPTH_TEST);
        gl.glDepthFunc(GL10.GL_LEQUAL);
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
        gl.glEnable(GL10.GL_NORMALIZE);
        gl.glShadeModel(GL10.GL_SMOOTH);
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);        //set background color
        gl.glMatrixMode(GL10.GL_PROJECTION);

        // Lighting
        gl.glEnable(GL10.GL_LIGHTING);
        gl.glLightModelfv(GL10.GL_LIGHT_MODEL_AMBIENT, getFloatBufferFromArray(new  float[]{0.5f,0.5f,0.5f,1.0f}));// 全局环境光
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT_AND_DIFFUSE, new float[]{0.3f, 0.3f, 0.3f, 1.0f}, 0);
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, new float[] { 0f, 0f, 1000f, 1.0f }, 0);
        gl.glEnable(GL10.GL_LIGHT0);


    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glMatrixMode(GL10.GL_PROJECTION);
        float aspectRatio = (float) width / height;
        gl.glViewport(0, 0, width, height);
        gl.glLoadIdentity();

        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        GLU.gluPerspective(gl, 90f, aspectRatio, 1f, 5000f);    //gl, fovy, width/height, near, far
        GLU.gluLookAt(gl, 0, 0, 110f, 0, 0, 0, 0, 1f, 0);       //gl, position xyz, pointer xyz, angle
        //gl.glRotatef(180, 0, 0, 1);
    }

    @Override
    public void onDrawFrame(GL10 gl) {

        //gl.glLoadIdentity();
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        //gl.glTranslatef(0, 0, -200);
        //gl.glTranslatef(20, 0, 0);
        //gl.glRotatef(45, 0, 1, 0);
        //gl.glRotatef(0, 1, 0, 0);
        //gl.glScalef(1, 1, 1);

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glMatrixMode(GL10.GL_MODELVIEW);

        //drawGrids(gl);
        gl.glLoadIdentity();
        gl.glRotatef(180, 0, 0, 1);
        gl.glRotatef(rotateAngle, rotateX, rotateY, rotateZ);

        // draw object
        if (stlObject != null) {
            // FIXME transparency applying does not correctly
            gl.glMaterialfv(GL10.GL_FRONT, GL10.GL_AMBIENT, new float[] { 0.75f,0.75f,0.75f,1.0f }, 0);

            gl.glMaterialfv(GL10.GL_FRONT, GL10.GL_DIFFUSE, new float[] { 0.75f,0.75f,0.75f,1.0f }, 0);

            gl.glEnable(GL10.GL_COLOR_MATERIAL);
            gl.glPushMatrix();
            gl.glColor4f(0.7f, 0.7f, 0.7f, 1.0f);
            stlObject.draw(gl);
            gl.glPopMatrix();
            gl.glDisable(GL10.GL_COLOR_MATERIAL);
        }
    }

    public void setRotation(float angle, float x, float y, float z){
        rotateAngle = angle;
        rotateX = x;
        rotateY = y;
        rotateZ = z;
    }

    private FloatBuffer getFloatBufferFromArray(float[] vertexArray) {
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertexArray.length * 4);
        vbb.order(ByteOrder.nativeOrder());
        FloatBuffer triangleBuffer = vbb.asFloatBuffer();
        triangleBuffer.put(vertexArray);
        triangleBuffer.position(0);
        return triangleBuffer;
    }

    private FloatBuffer getFloatBufferFromList(List<Float> vertexList) {
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertexList.size() * 4);
        vbb.order(ByteOrder.nativeOrder());
        FloatBuffer triangleBuffer = vbb.asFloatBuffer();
        float[] array = new float[vertexList.size()];
        for (int i = 0; i < vertexList.size(); i++) {
            array[i] = vertexList.get(i);
        }
        triangleBuffer.put(array);
        triangleBuffer.position(0);
        return triangleBuffer;
    }

    /**
     * 画网格
     * @param gl
     */
    private void drawGrids(GL10 gl) {
        List<Float> lineList = new ArrayList<Float>();

        for (int x = -100; x <= 100; x += 5) {
            lineList.add((float) x);
            lineList.add(-100f);
            lineList.add(0f);
            lineList.add((float)x);
            lineList.add(100f);
            lineList.add(0f);
        }
        for (int y = -100; y <= 100; y += 5) {
            lineList.add(-100f);
            lineList.add((float) y);
            lineList.add(0f);
            lineList.add(100f);
            lineList.add((float) y);
            lineList.add(0f);
        }

        FloatBuffer lineBuffer = getFloatBufferFromList(lineList);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, lineBuffer);

        gl.glLineWidth(2f);
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, new float[]{1.0f, 1.0f, 1.0f, 0.5f}, 0);
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, new float[]{1.0f, 1.0f, 1.0f, 0.1f}, 0);
        gl.glDrawArrays(GL10.GL_LINES, 0, lineList.size() / 3);
    }

    public void delete(){
        stlObject.delete();
        stlObject=null;
    }
}
